<style lang="scss" src="./index.scss" scoped></style>
<template>
    <div class="drag-tag-form-box">
        <draggable
                class="drag-tag-form__tbody"
                tag="div"
                :list="list"
                filter=".no-drag"
                v-bind="dragOptions"
                group="tagModel"
                @change="onDragChange"
                :move="onDragMove"
                @start="drag = true"
                @end="drag = false">
            <transition-group type="transition" :name="!drag ? 'flip-list' : null">
                    <template v-for="(item) in currentList">
                        <template v-if="item.itemType === 0">
                            <el-collapse class="form-collapse control-item" :class="{'selected-control': selectedControl.tempId === item.tempId, 'no-drag': oldName && currentItemId === item.tempId || currentItemId === item.id}" :key="item.tempId || item.id" :name="item.tempId || item.id" v-model="collapseActive">
                                <el-collapse-item :name="item.tempId">
                                    <template slot="title">
                                        <p class="control-item-name" v-if="currentItemId !== item.tempId && currentItemId !== item.id" style="width: 100%;margin: 0" @click.stop="clickControl(item)" @dblclick.stop="dblclickName(item)">{{item.name}}</p>
                                        <el-input class="normal-input-collapse" :ref="'editName' + item.tempId || item.id" v-model="item.name" v-if="oldName && currentItemId === item.tempId || currentItemId === item.id" @blur="changeName(item.name, item)"></el-input>
                                        <span class="delete-icon" v-if="selectedControl.tempId === item.tempId && !_isReadOnly" @click.stop="deleteControl(item)">
                                            <icon-svg name="icon-control-delete"></icon-svg>
                                        </span>
                                        <el-button type="text" style="margin-right: 20px;" icon="el-icon-plus" v-if="!_isReadOnly" @click.stop="addInGroupItem(item)">添加表单项</el-button>
                                    </template>
                                    <drag-tag-form
                                        :list.sync="item.items"
                                        @changeNowControl="changeNowControl"
                                        :checkHasBind="checkHasBind"
                                        :deleteBind="deleteBind"
                                        ref="dragTagFormRef">
                                    </drag-tag-form>
                                </el-collapse-item>
                            </el-collapse>
                        </template>
                        <template v-else-if="item.itemType === 1">
                            <div class="child-table control-item" :key="item.tempId || item.id" :class="{'selected-control': selectedControl.tempId === item.tempId, 'no-drag': oldName && currentItemId === item.tempId || currentItemId === item.id}" @click.stop="clickControl(item)">
                                <p class="control-item-name">
                                    <span v-if="currentItemId !== item.tempId && currentItemId !== item.id" @dblclick.stop="dblclickName(item)">{{item.name}}</span>
                                    <el-input class="normal-input normal-input-table" :ref="'editName' + item.tempId || item.id" v-model="item.name" v-if="oldName && currentItemId === item.tempId || currentItemId === item.id" @blur="changeName(item.name, item)"></el-input>
                                    <span class="delete-icon" v-if="selectedControl.tempId === item.tempId && !_isReadOnly" @click.stop="deleteControl(item)">
                                        <icon-svg name="icon-control-delete"></icon-svg>
                                    </span>
                                </p>
                                <div class="child-table-content" :class="{hasRight: _isReadOnly}">
                                    <div class="first child-table-item">
                                        <div class="title">序号</div>
                                        <div class="content">1</div>
                                    </div>
                                    <drag-tag-form
                                        :list.sync="item.items"
                                        :isTable="true"
                                        :checkHasBind="checkHasBind"
                                        :deleteBind="deleteBind"
                                        @changeNowControl="changeNowControl"
                                        ref="dragTagFormRef">
                                    </drag-tag-form>
                                    <div class="last child-table-item" v-if="!_isReadOnly">
                                        <el-button type="text" class="add-btn" @click="addFormOptions(item)">添加表单项</el-button>
                                    </div>
                                </div>
                            </div>
                        </template>
                        <template v-else-if="isTable">
                            <div class="child-table-item control-item" :class="{'selected-control': selectedControl.tempId === item.tempId, 'no-drag': oldName && currentItemId === item.tempId || currentItemId === item.id}" :key="item.tempId || item.id" @click.stop="clickControl(item)">
                                <span class="delete-icon" v-if="selectedControl.tempId === item.tempId && !_isReadOnly && currentList.length > 1" @click.stop="deleteControl(item)">
                                    <icon-svg name="icon-control-delete"></icon-svg>
                                </span>
                                <div class="title" :class="{'is_required': item.required && currentItemId !== item.tempId && currentItemId !== item.id}" :title="item.name">
                                    <span v-if="currentItemId !== item.tempId && currentItemId !== item.id" @dblclick.stop="dblclickName(item)">{{item.name}}{{ item.unitKindName ? `(${item.unitKindName})` : "" }}</span>
                                    <el-input :ref="'editName' + item.tempId || item.id" v-model="item.name" v-if="oldName && currentItemId === item.tempId || currentItemId === item.id" @blur="changeName(item.name, item)"></el-input>
                                </div>
                                <div class="content">
                                    <fill-in-table-item :item.sync="item" :modelData.sync="item"></fill-in-table-item>
                                </div>
                            </div>
                        </template>
                        <template v-else-if="item.itemType === 2">
                            <div class="form-item control-item" :class="{'selected-control': selectedControl.tempId === item.tempId, 'no-drag': oldName && currentItemId === item.tempId || currentItemId === item.id}" :key="item.tempId || item.id" @click.stop="clickControl(item)">
                                <span class="delete-icon" v-if="selectedControl.tempId === item.tempId && !_isReadOnly" @click.stop="deleteControl(item)">
                                    <icon-svg name="icon-control-delete"></icon-svg>
                                </span>
                                <p class="control-item-name" v-if="currentItemId !== item.tempId && currentItemId !== item.id" @dblclick.stop="dblclickName(item)" :class="{'is_required': item.required}">{{item.name}}{{ item.unitKindName ? `(${item.unitKindName})` : "" }}</p>
                                <el-input class="normal-input" :ref="'editName' + item.tempId || item.id" v-model="item.name" v-if="oldName && currentItemId === item.tempId || currentItemId === item.id" @blur="changeName(item.name, item)"></el-input>
                                <fill-in-item :item.sync="item"></fill-in-item>
                            </div>
                        </template>
                    </template>
                </transition-group>
        </draggable>
    </div>
</template>

<script lang="ts">
import { Component, Mixins, Prop, PropSync, Watch } from "vue-property-decorator";
import FillInItem from "@/views/module-manage/src/components/fill-in/item.vue";
import FillInTableItem from "@/views/module-manage/src/components/fill-in/table-item.vue";
import draggable from "vuedraggable";
import FormMixin from "@/mixins/form.mixin.base";
import { State } from "vuex-class";
import { getRandomId } from "@/utils";
@Component({
    name: "DragTagForm",
    components: {
        draggable,
        DragTagForm, // eslint-disable-line
        FillInItem,
        FillInTableItem
    }
})
export default class DragTagForm extends Mixins(FormMixin) {
    @State(state => state.selectedControl) selectedControl: any;

    drag = false;
    // 折叠面板默认展开
    collapseActive: any = [];
    // 只添加一次默认展开
    onceList: any = [];
    get dragOptions() {
        return {
            animation: 200,
            disabled: false,
            ghostClass: "ghost"
        };
    }

    get _isDetail() {
        return this.$route.query.isDetail === "1";
    }

    get requiredChecked(): boolean {
        const _length = this.currentList.filter((item: any) => item.required).length;
        return _length === this.currentList.length;
    }

    set requiredChecked(val: boolean) {
        for (let i = 0; i < this.currentList.length; i++) {
            const cur = this.currentList[i];
            cur.required = val;
        }
    }

    get _isReadOnly() {
        return this.$route.query.isDetail === '1' || this.$route.query.isSend === 'send';
    }

    typeList = [
        { id: "1", value: "input-text", label: "单行文本" },
        { id: "2", value: "input-textarea", label: "多行文本" },
        { id: "3", value: "input-date", label: "日期选择" },
        { id: "11", value: "input-datetime", label: "日期时间选择" },
        { id: "4", value: "location", label: "定位" },
        { id: "6", value: "select", label: "单选" },
        { id: "7", value: "cascader", label: "多选" },
        { id: "12", value: "input-num", label: "整数" },
        { id: "13", value: "input-num-decimal", label: "小数" },
        { id: "5", value: "upload-img", label: "上传图片" },
        { id: "8", value: "upload-video", label: "上传视频" },
        { id: "9", value: "upload-record", label: "上传录音" },
        { id: "10", value: "upload-file", label: "上传文件" }
    ];

    unitList = [];

    // 表格渲染格
    tableColumn = [
        { label: '标题', prop: 'name' },
        { label: '类型', prop: 'type' },
        { label: '单位', prop: 'unit' },
        { label: '选项操作', prop: 'optionValueText' },
        { label: '必填', prop: 'required' }
    ]

    // 是否是子表控件
    @Prop({
        type: Boolean,
        default: false
    })
    readonly isTable!: boolean;

    // 是否是子表控件
    @Prop({
        type: Function
    })
    readonly checkHasBind!: any;

    // 删除绑定关系
    @Prop({
        type: Function
    })
    readonly deleteBind!: any;

    @PropSync(
        'list',
        {
            type: Array,
            default: () => {
                return [];
            }
        })
    readonly currentList!: any[];

    @Watch("currentList", { deep: true })
    changeItemList() {
        this.currentList.map((item: any) => {
            if (item.itemType === 0) {
                return item.tempId;
            }
        }).forEach((item: any) => {
            if (!this.collapseActive.includes(item) && !this.onceList.includes(item)) {
                this.collapseActive.push(item);
                this.onceList.push(item);
            }
        });
    }

    oldName = ""
    currentItemId = ""

    mounted() {
        this.initSearchData();
    }

    handleItemClick(item: any, type: string) {
        this.$emit("item-click", item, type);
    }

    // 获取表单项类型/单位
    async initSearchData() {
        try {
            const typeResponse = await this.$server["moduleManage/form/type"]({
                loader: false
            });
            if (typeResponse.data.code !== 200) {
                throw typeResponse.data;
            }
            this.typeList = (typeResponse.data.data || []).map((item: any) => {
                return {
                    id: item.id || "",
                    value: item.value || "",
                    label: item.name || ""
                };
            });
        } catch (error) {
            if (error.cancel) {
                return;
            }
            this.$message.error(error.message || "接口请求错误!");
            throw error;
        }
    }

    onAdd(item?: any, number: any = 1, nameList?: any) {
        if (nameList) {
            nameList.forEach((it: any) => {
                const node = this.buildControlData(item.source || item, item.itemType, it);
                this.currentList.push(node);
            });
        } else {
            for (let i = 0; i < number; i++) {
                this.creatItem(item);
            }
        }
    }

    creatItem(item?: any) {
        if (item) {
            if ([0, 1, 2].includes(item.itemType)) {
                let node = this.buildControlData(item.source || item, item.itemType);
                if (item.itemType === 1) {
                    node = this.addChildControlItem(node);
                }
                this.currentList.push(node);
            } else {
                this.currentList.push(this.buildData(item.source || {}));
            }
        }
    }

    // 添加子表控件子项
    addChildControlItem(node: any) {
        if (node.items && node.items.length) return node;
        return {
            ...node,
            items: [{
                itemType: 2,
                tempId: getRandomId(),
                items: [],
                name: "表单项",
                valueKindId: "1",
                required: true,
                placeholder: "请输入"
            }]
        };
    }

    handleSelect(item: any, index: any) {
        const cur: any = item.source || {};
        const newItem = this.buildData(cur);
        newItem.tempId = this.currentList[index].tempId;
        this.$set(this.currentList, index, newItem);
    }

    buildData(cur: any) {
        let optionValueText = "";
        if (
            cur.valueLabel === "select" ||
            cur.valueLabel === "cascader"
        ) {
            (cur.optionIds || []).forEach(
                (subCur: any, index: any) => {
                    optionValueText +=
                        (index === 0 ? "" : ",") + subCur.name;
                }
            );
        }
        return {
            tempId: getRandomId(),
            name: cur.name || "",
            typeId: cur.valueKindId || "",
            typeValue: cur.valueLabel || "",
            type: cur.valueKindName || "",
            unitValue: cur.unitKindId || "",
            unit: cur.unitKindName || "",
            rules: cur.rules || "",
            optionId: cur.optionId || "",
            optionValueText: optionValueText,
            optionValueTextNew: "",
            required: this.requiredChecked || !!cur.required
        };
    }

    submit() {
        const res: any = {
            result: true,
            msg: ""
        };
        const getItem = (list: any) => {
            if (!list.length) return false;
            let flag = true;
            for (let i = 0; i < list.length; i++) {
                if (list[i].itemType === 0) {
                    if (!getItem(list[i].items)) {
                        flag = false;
                        break;
                    }
                } else if (list[i].itemType === 1) {
                    if (!list[i].items.length) {
                        flag = false;
                        break;
                    }
                } else if (list[i].itemType === 2) {
                    flag = true;
                }
            }
            return flag;
        };
        res.result = getItem(this.currentList);
        res.msg = "请确认有表单项或分组和表格控件中至少有一个表单项";
        return res;
    }

    // 根据资源项导入的
    onAddImport(list: any) {
        for (let i = 0; i < list.length; i++) {
            const node = this.buildControlData(list[i], 2);
            this.currentList.push(node);
        }
    }

    // 分组/子表控件 表单项默认配置
    buildControlData(cur: any, itemType: any, name?: any) {
        return {
            tempId: getRandomId(),
            name: name || cur.name || "",
            _key: undefined,
            itemType,
            options: cur.options || [],
            items: cur.items || [],
            valueKindId: itemType === 2 ? cur.valueKindId || "1" : undefined,
            required: cur.required !== false,
            fillType: ["3", "11"].includes(cur.valueKindId) ? cur.fillType || "date" : undefined,
            placeholder: cur.placeholder || "请输入",
            valueLength: cur.valueKindId === "12" ? cur.valueLength || "" : ""
        };
    }

    // 表单项默认配置
    onDragChange(item: any) {
        if (!item.added) return;
        const { newIndex, element } = item.added;
        let e: any = element;
        if (e.batch) {
            this.onAdd(e, Number(e._number));
            return;
        }
        if (e.boxFlag) {
            const options = e.list.map((cur: any) => {
                return { name: cur, tempId: getRandomId() };
            });
            e = {
                ...e,
                itemType: 2,
                name: e.dropDownBoxName,
                valueKindId: e.boxFlag.toString(),
                options
            };
        }
        e.valueLength = e.valueKindId === "12" ? e.valueLength || "" : "";
        switch (e.itemType) {
        case 0:
            this.$set(this.currentList, newIndex, this.buildControlData(e || {}, 0));
            break;
        case 1:
            this.$set(this.currentList, newIndex, this.addChildControlItem(this.buildControlData(e || {}, 1)));
            break;
        case 2:
            this.$set(this.currentList, newIndex, this.buildControlData(e || {}, 2));
            break;
        default:
            this.$set(this.currentList, newIndex, this.buildData(e.tempId ? e : e.source || {}));
            break;
        }
    }

    onDragMove(e: any) {
        if (this._isReadOnly) return false;
        const { draggedContext, relatedContext } = e;
        const className2 = this.getParentClassName(relatedContext.component.$el, 2).className;
        if (draggedContext.element.itemType === 1 && className2 === "child-table-content") {
            return false;
        }
        if (draggedContext.element.itemType === 0 && className2 === "child-table-content") {
            return false;
        }
        if (draggedContext.element.itemType === 0 && className2 === "el-collapse-item__content") {
            return false;
        }
        if (draggedContext.element.itemType === 2 && className2 === "child-table-content") {
            if (draggedContext.element.cascadeId) {
                this.checkTime();
                return false;
            } else {
                if (!this.checkHasBind(draggedContext.element)) {
                    this.checkTime();
                    return false;
                }
            }
        }
    }

    checkTime() {
        const getMsgTime: any = window.sessionStorage.getItem("messageTime") || 0;
        if (!getMsgTime || new Date().getTime() - Number(getMsgTime) > 2000) {
            this.$message.error("请先解除表单项上面绑定的显示条件");
        }
        window.sessionStorage.setItem("messageTime", new Date().getTime().toString());
    }

    // 获取父级组件class
    getParentClassName(node: any, n: number) {
        let e = node;
        for (let i = 0; i < n; i++) {
            e = e ? e.parentElement : "";
        }
        return e || {};
    }

    // 点击控件
    clickControl(item: any) {
        if (this._isReadOnly) return;
        this.$store.dispatch("updateSelectedControl", {
            tempId: item.tempId
        });
        this.$emit("changeNowControl", item);
    }

    // 递归触发
    changeNowControl(item: any) {
        this.$emit("changeNowControl", item);
    }

    // 在分组中添加表单项
    addInGroupItem(item: any) {
        const obj = {
            _key: undefined,
            tempId: getRandomId(),
            itemType: 2,
            items: [],
            name: "表单项",
            options: [],
            valueKindId: "1",
            required: true,
            placeholder: "请输入"
        };
        item.items.push(obj);
    }

    // 删除控件
    deleteControl(item: any) {
        if (this._isReadOnly) return;
        if ([0, 1].includes(item.itemType)) {
            this.$confirm("是否确认删除?", "提示")
                .then(() => {
                    this.toDelete(item);
                })
                .catch();
        } else {
            this.toDelete(item);
        }
    }

    toDelete(item: any) {
        if (item.itemType === 0) {
            const index = this.currentList.findIndex((it: any) => it.tempId === item.tempId);
            if (index !== -1) {
                this.currentList.splice(index, 1);
            }
            if (this.collapseActive.includes(item.tempId)) {
                this.collapseActive.splice(this.collapseActive.indexOf(item.tempId), 1);
            }
            return;
        } else if (item.itemType === 2) {
            this.deleteBind(item);
        }
        const del = (arr: any) => {
            for (let i = 0; i < arr.length; i++) {
                const index = arr.findIndex((it: any) => it.tempId === item.tempId);
                if (index !== -1) {
                    arr.splice(index, 1);
                } else if (arr[i].items && arr[i].items.length) {
                    del(arr[i].items);
                }
            }
        };
        del(this.currentList);
    }

    // 添加自定义表单项
    addFormOptions(item: any) {
        const obj = {
            _key: undefined,
            tempId: getRandomId(),
            itemType: 2,
            items: [],
            name: "表单项",
            options: [],
            valueKindId: "1",
            required: true,
            placeholder: "请输入"
        };
        item.items.push(obj);
    }

    // 双击改名
    dblclickName(item: any) {
        if (this._isReadOnly || this._isDetail) return false;
        this.oldName = item.name;
        this.currentItemId = item.tempId || item.id;
        this.$nextTick(() => {
            (this.$refs["editName" + this.currentItemId] as any)[0].focus();
        });
    }

    changeName(val: any, item: any) {
        if (!val) {
            item.name = this.oldName;
        }
        this.oldName = "";
        this.currentItemId = "";
    }
}
</script>
